package com.jumper.property.comparer.diff;

import com.jumper.property.comparer.core.bean.RootSetting;
import com.jumper.property.comparer.diff.getter.ArrayDiffGetter;
import com.jumper.property.comparer.diff.getter.CombinationDiffGetter;
import com.jumper.property.comparer.diff.getter.ObjectDiffGetter;
import com.jumper.property.comparer.diff.getter.PropertyDiffGetter;
import com.jumper.property.comparer.pattern.DiffPattern;
import com.jumper.property.comparer.core.result.DiffResult;
import com.jumper.property.comparer.setting.SettingResolveImpl;
import com.jumper.property.comparer.setting.SettingResolver;
import com.jumper.property.comparer.spi.SPILoader;
import com.jumper.property.comparer.util.StringUtils;
import com.jumper.property.comparer.util.ValueUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class DefaultDiffResolver implements DiffResolver {
    public final static DiffResolver RESOLVER = new DefaultDiffResolver();
    private final SettingResolver resolver = new SettingResolveImpl();
    private final DiffPattern pattern = SPILoader.load(DiffPattern.class);

    @Override
    public DiffResult getDifference(Class<?> cls, Object beforeValue, Object afterValue) {
        List<DiffVal> diffValList = getDifferenceList(cls, beforeValue, afterValue);
        List<String> diffValues = diffValList.stream().map(DiffVal::getDiffValue).collect(Collectors.toList());
        String diffs = String.join(pattern.getDiffJoinPattern(), diffValues);
        return new DiffResult(diffs, diffValList, !StringUtils.isEmpty(diffs));
    }

    private List<DiffVal> getDifferenceList(Class<?> cls, Object beforeValue, Object afterValue) {
        List<DiffVal> diffs = new ArrayList<>();
        RootSetting root = resolver.resolve(cls);
        // 基本属性处理
        root.getPropertySettings().forEach(setting -> {
            diffs.addAll(new PropertyDiffGetter().getDiffs(new Element<>(
                    beforeValue,
                    afterValue,
                    setting
            )));
        });
        // 分组属性处理
        root.getCombinationSettings().forEach(setting -> {
            diffs.addAll(new CombinationDiffGetter().getDiffs(new Element<>(
                    beforeValue,
                    afterValue,
                    setting
            )));
        });
        // 对象属性处理
        root.getObjectSettings().forEach(setting -> {
            diffs.addAll(new ObjectDiffGetter().getDiffs(new Element<>(
                    beforeValue,
                    afterValue,
                    setting
            )));
        });
        // 列表属性处理
        root.getArraySettings().forEach(setting -> {
            Field field = setting.getField();
            diffs.addAll(new ArrayDiffGetter().getDiffs(new Element<>(
                    ValueUtil.getValue(beforeValue, field),
                    ValueUtil.getValue(afterValue, field),
                    setting
            )));
        });
        return diffs;
    }
}
